﻿using Admin.NET.Application.Entity;

using Admin.NET.Application.Helper;
using Admin.NET.Core.Service;
using DocumentFormat.OpenXml.Wordprocessing;
using Magicodes.ExporterAndImporter.Core;
using Magicodes.ExporterAndImporter.Excel;
using Microsoft.AspNetCore.Http;
using NewLife.Caching;
using System.Data;

namespace Admin.NET.Application;

/// <summary>
/// 从机变量服务
/// </summary>
[ApiDescriptionSettings(ApplicationConst.GroupName, Order = 100)]
public class DeviceSlaveTemplatePointsService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<DeviceSlaveTemplatePoints> _deviceSlaveTemplatePointsRep;
    private readonly SysFileService sysFileService;

    public DeviceSlaveTemplatePointsService(SqlSugarRepository<DeviceSlaveTemplatePoints> deviceSlaveTemplatePointsRep, SysFileService sysFileService)
    {
        _deviceSlaveTemplatePointsRep = deviceSlaveTemplatePointsRep;
        this.sysFileService = sysFileService;
    }

    /// <summary>
    /// 分页查询从机变量
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Page")]
    [DisplayName("分页查询从机变量")]
    public async Task<SqlSugarPagedList<DeviceSlaveTemplatePointsOutput>> Page(PageDeviceSlaveTemplatePointsInput input)
    {
        input.SearchKey = input.SearchKey?.Trim();
        var query = _deviceSlaveTemplatePointsRep.AsQueryable()
            .WhereIF(!string.IsNullOrEmpty(input.SearchKey), u =>
                u.PointName.Contains(input.SearchKey)
                || u.Len.Contains(input.SearchKey)
                || u.Unit.Contains(input.SearchKey)
            )
            .WhereIF(!string.IsNullOrWhiteSpace(input.PointName), u => u.PointName.Contains(input.PointName.Trim()))
            .WhereIF(input.DeviceSlaveTemplateId > 0, u => u.DeviceSlaveTemplateId == input.DeviceSlaveTemplateId)
            .WhereIF(!string.IsNullOrWhiteSpace(input.Len), u => u.Len.Contains(input.Len.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Unit), u => u.Unit.Contains(input.Unit.Trim()))
            .WhereIF(input.PrecisionEnum.HasValue, u => u.PrecisionEnum == input.PrecisionEnum)
            //处理外键和TreeSelector相关字段的连接
            .LeftJoin<DeviceSlaveTemplate>((u, deviceslavetemplateid) => u.DeviceSlaveTemplateId == deviceslavetemplateid.Id)
            .Select((u, deviceslavetemplateid) => new DeviceSlaveTemplatePointsOutput
            {
                Id = u.Id,
                PointType = u.PointType,
                PointName = u.PointName,
                DeviceSlaveTemplateId = u.DeviceSlaveTemplateId,
                DeviceSlaveTemplateIdSlaveName = deviceslavetemplateid.SlaveName,
                DataIdentifier = u.DataIdentifier,
                Millennials = u.Millennials,
                DataType = u.DataType,
                Len = u.Len,
                reg = u.reg,
                RegType = u.RegType,
                VarType = u.VarType,
                Unit = u.Unit,
                ReadWrite = u.ReadWrite,
                Store = u.Store,
                Cycle = u.Cycle,
                CreateTime = u.CreateTime,
                UpdateTime = u.UpdateTime,
                CreateUserId = u.CreateUserId,
                CreateUserName = u.CreateUserName,
                UpdateUserId = u.UpdateUserId,
                UpdateUserName = u.UpdateUserName,
                IsDelete = u.IsDelete,
                PrecisionEnum = (PrecisionEnum)u.PrecisionEnum,
                Formula = u.Formula,
                ReFormula = u.ReFormula
            });
        var pagelist = await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
        foreach (var item in pagelist.Items)
        {
            item.reg = ((int)item.RegType + "").PadRight(5 - item.reg.Length, '0') + item.reg;
        }

        return pagelist;
    }

    /// <summary>
    /// 增加从机变量
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Add")]
    [DisplayName("增加从机变量")]
    public async Task<long> Add(AddDeviceSlaveTemplatePointsInput input)
    {
        var entity = input.Adapt<DeviceSlaveTemplatePoints>();
        await _deviceSlaveTemplatePointsRep.InsertAsync(entity);
        return entity.Id;
    }

    /// <summary>
    /// 删除从机变量
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Delete")]
    [DisplayName("删除从机变量")]
    public async Task Delete(DeleteDeviceSlaveTemplatePointsInput input)
    {
        var entity = await _deviceSlaveTemplatePointsRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
        await _deviceSlaveTemplatePointsRep.FakeDeleteAsync(entity);   //假删除
        //await _deviceSlaveTemplatePointsRep.DeleteAsync(entity);   //真删除
    }

    /// <summary>
    /// 删除模板下的从机变量
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "DeleteByDeviceSlaveTemplateId")]
    [DisplayName("删除模板下的从机变量")]
    public async Task DeleteByDeviceSlaveTemplateId(DeleteDeviceSlaveTemplatePointsInput input)
    {
        await _deviceSlaveTemplatePointsRep.Context.Deleteable<DeviceSlaveTemplatePoints>().Where(u => u.DeviceSlaveTemplateId == input.Id).ExecuteCommandAsync();
    }

    /// <summary>
    /// 更新从机变量
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Update")]
    [DisplayName("更新从机变量")]
    public async Task Update(UpdateDeviceSlaveTemplatePointsInput input)
    {
        var entity = input.Adapt<DeviceSlaveTemplatePoints>();
        await _deviceSlaveTemplatePointsRep.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
    }

    /// <summary>
    /// 获取从机变量
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "Detail")]
    [DisplayName("获取从机变量")]
    public async Task<DeviceSlaveTemplatePoints> Detail([FromQuery] QueryByIdDeviceSlaveTemplatePointsInput input)
    {
        return await _deviceSlaveTemplatePointsRep.GetFirstAsync(u => u.Id == input.Id);
    }

    /// <summary>
    /// 获取从机变量列表
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "List")]
    [DisplayName("获取从机变量列表")]
    public async Task<List<DeviceSlaveTemplatePointsOutput>> List([FromQuery] PageDeviceSlaveTemplatePointsInput input)
    {
        return await _deviceSlaveTemplatePointsRep.AsQueryable().Select<DeviceSlaveTemplatePointsOutput>().ToListAsync();
    }

    /// <summary>
    /// 获取设备从机模板Id列表
    /// </summary>
    /// <returns></returns>
    [ApiDescriptionSettings(Name = "DeviceSlaveTemplateDeviceSlaveTemplateIdDropdown"), HttpGet]
    [DisplayName("获取设备从机模板Id列表")]
    public async Task<dynamic> DeviceSlaveTemplateDeviceSlaveTemplateIdDropdown()
    {
        return await _deviceSlaveTemplatePointsRep.Context.Queryable<DeviceSlaveTemplate>()
                .Select(u => new
                {
                    Label = u.SlaveName,
                    Value = u.Id
                }
                ).ToListAsync();
    }

    /// <summary>
    /// 上传文件 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("变量导入")]
    public async Task<object> UploadFile([FromForm] FileUploadPointsInput input)
    {
        // 判断文件类型是否是Excel类型
        if (input.File == null || !input.File.FileName.EndsWith(".xlsx"))
        {
            return false;
        }

        using (var stream = input.File.OpenReadStream())
        {
            IImporter importer = new ExcelImporter();
            var importResult = await importer.Import<DeviceSlaveTemplatePointsInput>(stream);

            if (importResult.HasError)
            {
                var list = importResult.TemplateErrors.Select(u => u.RequireColumnName + ":" + u.Message).ToList();
                return new { IsSuccess = false, Messages = list };
            }

            //校验必填的枚举的转换
            var data = importResult.Data;
            var errorList = new List<string>();
            foreach (var item in data)
            {
                var dataType = EnumHelper.GetEnumByDescription<Entity.DataType>(item.DataType);
                var store = EnumHelper.GetEnumByDescription<StoreType>(item.Store);
                var cycle = EnumHelper.GetEnumByDescription<CycleType>(item.Cycle);
                var readWrite = EnumHelper.GetEnumByDescription<ReadWrite>(item.ReadWrite);

                var errors = new List<string>();

                if (dataType == null) errors.Add($"{item.DataType}格式不正确");
                if (store == null) errors.Add($"{item.Store}格式不正确");
                if (cycle == null) errors.Add($"{item.Cycle}格式不正确");
                if (readWrite == null) errors.Add($"{item.ReadWrite}格式不正确");

                if (errors.Any())
                {
                    errorList.Add(item.PointName + ":" + string.Join(", ", errors));
                }
            }

            if (errorList.Any())
            {
                return new { IsSuccess = false, Messages = errorList };
            }

            foreach (var item in data)
            {
                DeviceSlaveTemplatePoints deviceSlaveTemplatePoints = new DeviceSlaveTemplatePoints()
                {
                    PointName = item.PointName,
                    Unit = item.Unit,
                    RegType = (Entity.RegType)(item.RegType),
                    DataType = EnumHelper.GetEnumByDescription<Entity.DataType>(item.DataType).Value,
                    reg = item.reg,
                    VarType = item.VarType,
                    PrecisionEnum = item.PrecisionEnum.HasValue ? (PrecisionEnum)item.PrecisionEnum.Value : PrecisionEnum.NoTenth,
                    Store = EnumHelper.GetEnumByDescription<StoreType>(item.Store).Value,
                    Cycle = EnumHelper.GetEnumByDescription<Entity.CycleType>(item.Cycle).Value,
                    ReadWrite = EnumHelper.GetEnumByDescription<Entity.ReadWrite>(item.ReadWrite).Value,
                    DataIdentifier = item.DataIdentifier,
                    Formula = item.Formula,
                    ReFormula = item.ReFormula,
                    DeviceSlaveTemplateId = input.DeviceSlaveTemplateId
                };

                //添加到数据库中
                await _deviceSlaveTemplatePointsRep.InsertAsync(deviceSlaveTemplatePoints);
            }
        }
        return new { IsSuccess = true };
    }

    /// <summary>
    /// 变量导出xslx文件
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "ExportPoints")]
    [DisplayName("变量导出xslx文件")]
    public async Task<IActionResult> ExportPoints([FromQuery] QueryByIdDeviceSlaveTemplatePointsInput input)
    {
        //根据DeviceSlaveTemplateId获取所有的变量
        var points = await _deviceSlaveTemplatePointsRep.AsQueryable()
           .Where(p => p.DeviceSlaveTemplateId == input.Id)
           .ToListAsync();
   

        var exporter = new ExcelExporter();
        //转成 DeviceSlaveTemplatePointsInput
        var data = points.Select(
            u => new DeviceSlaveTemplatePointsInput
            {
                PointName = u.PointName,
                Unit = u.Unit,
                RegType = (int)u.RegType,
                DataType = EnumHelper.GetDescriptionByEnum(u.DataType),
                reg = u.reg,
                VarType = u.VarType,
                PrecisionEnum = (int)u.PrecisionEnum,
                Store = u.Store.HasValue ? "" : EnumHelper.GetDescriptionByEnum(u.Store.Value),
                Cycle = EnumHelper.GetDescriptionByEnum(u.Cycle),
                ReadWrite = EnumHelper.GetDescriptionByEnum(u.ReadWrite),
                DataIdentifier = u.DataIdentifier,
                Formula = u.Formula,
                ReFormula = u.ReFormula
            }
            ).ToList();
        // 导出为Excel文件
        var fileBytes = await exporter.ExportAsByteArray(data);

        // 将文件保存到临时路径
        var stream = new MemoryStream(fileBytes);

        // 设置文件名
        var fileName = "exportedData.xlsx";
        return new FileStreamResult(stream, "application/octet-stream")
        {
            FileDownloadName = $"DeviceSlaveTemplatePoints_{input.Id}.xlsx"
        };
    }

    //return new FileStreamResult(new FileStream(path, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName + file.Suffix

    /// <summary>
    /// 获取设备从机模板变量的模板
    /// </summary>
    /// <returns></returns>
    [ApiDescriptionSettings(Name = "GetImportFileTemplate"), HttpGet]
    [DisplayName("获取设备从机模板变量的模板")]
    public async Task<SysFile> GetImportFileTemplate()
    {
        var filesPage = await sysFileService.Page(new PageFileInput() { FileName = "从机变量导入模板" });
        if (filesPage.Items.Count() == 0)
        {
            throw Oops.Oh(ErrorCodeEnum.Device001);
        }

        return filesPage.Items.FirstOrDefault();
    }

    public class FileUploadPointsInput : FileUploadInput
    {
        public long DeviceSlaveTemplateId { get; set; }
    }

    public class DeviceSlaveTemplatePointsInput
    {
        [ImporterHeader(Name = "变量名称（必填）")]
        [ExporterHeader(DisplayName = "变量名称（必填）")]
        [Required(ErrorMessage = "变量名称不能为空")]
        public string PointName { get; set; }

        [ImporterHeader(Name = "单位（选填）")]
        [ExporterHeader(DisplayName = "单位（选填）")]
        public string? Unit { get; set; }

        [ImporterHeader(Name = "寄存器类型")]
        [ExporterHeader(DisplayName = "寄存器类型")]
        [Required(ErrorMessage = "寄存器类型不能为空")]
        public int RegType { get; set; }

        [ImporterHeader(Name = "数据格式（必填）")]
        [ExporterHeader(DisplayName = "数据格式（必填）")]
        [Required(ErrorMessage = "数据格式不能为空")]
        public string DataType { get; set; }

        [ImporterHeader(Name = "一级地址")]
        [ExporterHeader(DisplayName = "一级地址")]
        public string reg { get; set; }

        [ImporterHeader(Name = "二级地址")]
        [ExporterHeader(DisplayName = "二级地址")]
        public string? VarType { get; set; }

        [ImporterHeader(Name = "小数位数")]
        [ExporterHeader(DisplayName = "小数位数")]
        public int? PrecisionEnum { get; set; }

        [ImporterHeader(Name = "存储方式（必填）")]
        [ExporterHeader(DisplayName = "存储方式（必填）")]
        [Required(ErrorMessage = "存储方式不能为空")]
        public string Store { get; set; }

        [ImporterHeader(Name = "采集频率（必填）")]
        [ExporterHeader(DisplayName = "采集频率（必填）")]
        [Required(ErrorMessage = "采集频率不能为空")]
        public string Cycle { get; set; }

        [ImporterHeader(Name = "读写方式（必填）")]
        [ExporterHeader(DisplayName = "读写方式（必填）")]
        [Required(ErrorMessage = "读写方式不能为空")]
        public string ReadWrite { get; set; }

        [ImporterHeader(Name = "变量标识（选填）")]
        [ExporterHeader(DisplayName = "变量标识（选填）")]
        public string? DataIdentifier { get; set; }

        [ImporterHeader(Name = "采集公式（选填）")]
        [ExporterHeader(DisplayName = "采集公式（选填）")]
        public string? Formula { get; set; }

        [ImporterHeader(Name = "控制公式（选填）")]
        [ExporterHeader(DisplayName = "控制公式（选填）")]
        public string? ReFormula { get; set; }
    }
}